﻿#include <iostream>
#include <fstream>

#include <nlohmann/json.hpp>

#include <Eigen/Core>

using json = nlohmann::json;
using namespace nlohmann::literals;

using namespace Eigen;

template<typename type_, unsigned rows, unsigned cols>
class MyMatrix {
public:
    Matrix<type_, rows, cols> matrix_;

public:
    MyMatrix() = default;
    MyMatrix(Matrix<type_, rows, cols> matrix_in) : matrix_(matrix_in){
        for (int i = 0; i < rows; ++i) {
            std::vector<type_> tmp_vec;
            for (int j = 0; j < cols; ++j) {
                tmp_vec.template emplace_back(matrix_(i, j));
            }
            matrix_data_.template emplace_back(tmp_vec);
        }
    }

    ~MyMatrix() = default;

    void vectors2matrix() {
        int r = 0, c = 0;
        for (auto i : this->matrix_data_) {
            c = 0;
            for (auto j : i) {
                this->matrix_(r, c) = j;
                // std::cout << j << std::endl;
                c++;
            }
            r++;
        }
    }

    friend void to_json(nlohmann::json& nlohmann_json_j, const MyMatrix& nlohmann_json_t)
    {
        nlohmann_json_j["matrix"] = nlohmann_json_t.matrix_data_;
//        nlohmann_json_j["address"] = nlohmann_json_t.address;
//        nlohmann_json_j["age"] = nlohmann_json_t.age;
    }

    friend void from_json(const nlohmann::json& nlohmann_json_j, MyMatrix& nlohmann_json_t)
    {
        nlohmann_json_t.matrix_data_ = nlohmann_json_j.at("matrix");
//        nlohmann_json_t.address = nlohmann_json_j.at("address");
//        nlohmann_json_t.age = nlohmann_json_j.at("age");

        nlohmann_json_t.vectors2matrix();
    }

private:
    std::vector< std::vector<double>> matrix_data_;
};

int load(std::string file_path, json &re) try {
    json l1;
    std::ifstream(file_path) >> l1;
    // json.at("Path").get_to(path);
//    std::cout << l1 << std::endl;
    re = l1;
    return 0;
}
catch (json::exception& e)
{
    std::cout << "deserialization failed: " << e.what() << std::endl;
    return  -1;
}

int save(std::string file_path, json re) try {
    std::ofstream(file_path) << re;
    return 0;
}
catch (json::exception& e)
{
    std::cout << "deserialization failed: " << e.what() << std::endl;
    return  -1;
}

int main() try{
    std::string json_path = "/home/hrl/Desktop/MyLearning/MyCppLearning/nlohmann-learning/json4Eigen/json4Matrix/matrix.json";
    // Matrix3d 实质上是 Eigen::Matrix<double, 3, 3>
    Matrix3d matrix_33 = Matrix3d::Zero(); //初始化为零

    // 实例化模板类
    MyMatrix<double, 3, 3> m33 = matrix_33;

    // serialization: MyMatrix -> json
    json j = m33;
    std::cout << "serialization: " << j << std::endl;

    // load json file need #include <fstream>
    json j1;
    load(json_path, j1);
    std::cout << "serialization: " << j1 << std::endl;
    std::cout << "serialization of dump: " << j1.dump(1) << std::endl;

    Matrix3d matrix_33_01 = Matrix3d::Zero();
    MyMatrix<double, 3, 3> m33_01 = matrix_33_01;
    m33_01 = j1.get<MyMatrix<double, 3, 3> >();
    std::cout << m33_01.matrix_ << std::endl;

    save(json_path, j1);
}
catch (std::exception &err) {
    std::cout << "std error is: " << err.what() << std::endl;
}
catch (json::exception& e)
{
    std::cout << "deserialization failed: " << e.what() << std::endl;
}
